package cn.yudao.basic.service.impl;

import cn.yudao.basic.constant.BaseConstants;
import cn.yudao.basic.dto.LoginDto;
import cn.yudao.basic.dto.RegisterPhoneDto;
import cn.yudao.basic.dto.WxDto;
import cn.yudao.basic.exception.BusinessException;
import cn.yudao.basic.jwt.JwtUtils;
import cn.yudao.basic.jwt.RsaUtils;
import cn.yudao.basic.jwt.UserInfo;
import cn.yudao.basic.mapper.LoginMapper;
import cn.yudao.basic.service.ILoginService;
import cn.yudao.basic.utils.AjaxResult;
import cn.yudao.basic.utils.HttpUtil;
import cn.yudao.basic.utils.MD5Utils;
import cn.yudao.basic.utils.StrUtils;
import cn.yudao.system.domain.Menu;
import cn.yudao.system.mapper.MenuMapper;
import cn.yudao.system.mapper.PermissionMapper;
import cn.yudao.user.domain.Logininfo;
import cn.yudao.user.domain.User;
import cn.yudao.user.domain.Wxuser;
import cn.yudao.user.mapper.LogininfoMapper;
import cn.yudao.user.mapper.UserMapper;
import cn.yudao.user.mapper.WxuserMapper;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxuserMapper wxuserMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Value("${jwt.rsa.pri}")
    private String priKey;

    /**
     * @Title: loginAccount
     * @Description: 账号登录token无状态登录
     * @Author: Mr.Jia
     * @Version: 1.0
     * @Date: 2022/7/8 21:58
     * @Parameters:
     * @Return
     */
//    @Override
//    public Map<String, Object> loginAccount(LoginDto loginDto) {
//        String password = loginDto.getPassword();
//        String type = loginDto.getType();
//        String username = loginDto.getUsername();
//        // 判断是否为空
//        if (StringUtils.isEmpty(password.trim()) || StringUtils.isEmpty(type) || StringUtils.isEmpty(username.trim())) {
//            throw new BusinessException("请输入你的账号密码");
//        }
//        // 根据账号和type去数据库查询
//        Logininfo logininfo = logininfoMapper.loadByUsername(username, type);
//        // 判断账号是否存在
//        if (logininfo == null) {
//            throw new BusinessException("账号密码错误");
//        }
//        // 判断密码是否正确
//        String salt = logininfo.getSalt();
//        String passwordValue = MD5Utils.encrypByMd5(salt + password);
//        if (!passwordValue.equals(logininfo.getPassword())) {
//            throw new BusinessException("账号密码错误");
//        }
//        // 将其保存到redis中
//        String token = UUID.randomUUID().toString();
//        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
//        // 装到map中
//        logininfo.setSalt("");
//        logininfo.setPassword("");
//
//        Map<String, Object> map = new HashMap<>();
//        map.put("token", token);
//        map.put("logininfo", logininfo);
//
//        return map;
//    }

    /**
     * @Title: loginPhoneCode
     * @Description: 手机验证码登录无状态token版本
     * @Author: Mr.Jia
     * @Version: 1.0
     * @Date: 2022/7/8 21:58
     * @Parameters:
     * @Return
     */
//    @Override
//    public Map<String, Object> loginPhoneCode(LoginDto loginDto) {
//        String registerCode = loginDto.getRegisterCode();
//        String type = loginDto.getType();
//        String phone = loginDto.getPhone();
//        // 判断是否为空
//        if (StringUtils.isEmpty(registerCode.trim()) || StringUtils.isEmpty(type) || StringUtils.isEmpty(phone.trim())) {
//            throw new BusinessException("请输入你的手机号及验证码");
//        }
//        // 判断手机号是否同一个
//        String redisPhoneCodeKey = BaseConstants.VerifyCodeConstant.BUSINESS_LOGIN_KEY + phone;
//        Object redisPhoneCodeValueTmp = redisTemplate.opsForValue().get(redisPhoneCodeKey);
//        if (redisPhoneCodeValueTmp == null) {
//            throw new BusinessException("请输入正确的手机号");
//        }
//        String[] split = redisPhoneCodeValueTmp.toString().split(":");
//        String redisPhoneCodeValue = split[1];
//        // 判断验证码是否正确
//        if (!redisPhoneCodeValue.equalsIgnoreCase(registerCode)) {
//            throw new BusinessException("手机验证码错误");
//        }
//        // 判断用户是否存在
//        Logininfo logininfo = logininfoMapper.loadByUsername(phone, type);
//        if (logininfo == null) {
//            throw new BusinessException("用户不存在");
//        }
//        // 获得redis的key=token
//        String token = UUID.randomUUID().toString();
//        // 存放数据到redis中
//        redisTemplate.opsForValue().set(token, logininfo);
//        // 装到map中
//        logininfo.setSalt("");
//        logininfo.setPassword("");
//        Map<String, Object> map = new HashMap<>();
//        map.put("token", token);
//        map.put("logininfo", logininfo);
//        return map;
//    }


    /**
     * @Title: wechat
     * @Description: 判断用户微信是否绑定了账号免密登录无状态token版本
     * @Author: Mr.Jia
     * @Version: 1.0
     * @Date:  2022/7/10 21:06
     * @Parameters:
     * @Return
     */
//    @Override
//    public AjaxResult wechat(WxDto wxDto) {
//        // 判断code是否为空
//        String code = wxDto.getCode();
//        if (StringUtils.isEmpty(code)) {
//            throw new BusinessException("系统异常请稍后再试！！");
//        }
//        // 获得wx开放平台的用户的基本信息
//        String jsonTokenOpenid = HttpUtil.httpGet(BaseConstants.WxConstant.WX_ACCESS_TOKEN_URL
//                .replace("APPID", BaseConstants.WxConstant.WX_APPID)
//                .replace("SECRET", BaseConstants.WxConstant.WX_SECRET)
//                .replace("CODE", code));
//        // 将json转换为对象
//        JSONObject jsonObject = JSONObject.parseObject(jsonTokenOpenid);
//        // 获取openid和access_token值
//        String accessToken = jsonObject.getString("access_token");
//        String openId = jsonObject.getString("openid");
//        // 根据openId从数据库中查询是否有值
//        Wxuser wxuser = wxuserMapper.loadByOpenId(openId);
//        // 判断wxuser是否存在
//        if (wxuser != null) {
//            // 根据wxuser的userid获取logininfo对象
//            Logininfo logininfo = logininfoMapper.loadByUserId(wxuser.getUserId());
//            // 获得redis的key=token
//            String token = UUID.randomUUID().toString();
//            // 存放数据到redis中
//            redisTemplate.opsForValue().set(token, logininfo);
//            // 装到map中
//            logininfo.setSalt("");
//            logininfo.setPassword("");
//            Map<String, Object> map = new HashMap<>();
//            map.put("token", token);
//            map.put("logininfo", logininfo);
//            return AjaxResult.me().setResult(map);
//        }
//        // 拼接地址
//        String binderUrl = "?accessToken=" + accessToken + "&openId=" + openId;
//        // 返回
//        return AjaxResult.me().setSuccess(false).setMessage("nobinder").setResult(binderUrl);
//    }



    /**
     * @Title: wechatBinder
     * @Description: 给用户绑定账号无状态token登录版本
     * @Author: Mr.Jia
     * @Version: 1.0
     * @Date:  2022/7/10 21:06
     * @Parameters:
     * @Return
     */
//    @Override
//    public Map wechatBinder(WxDto wxDto) {
//        // 非空判断
//        String openId = wxDto.getOpenId();
//        String phone = wxDto.getPhone();
//        String verifyCode = wxDto.getVerifyCode();
//        String accessToken = wxDto.getAccessToken();
//        if (StringUtils.isEmpty(openId)
//                || StringUtils.isEmpty(phone)
//                || StringUtils.isEmpty(verifyCode)
//                || StringUtils.isEmpty(accessToken)){
//            throw new BusinessException("系统参数为空！！");
//        }
//        // 根据phone查询user表是否有数据
//        User user = userMapper.loadByPhone(phone);
//        Logininfo logininfo = null;
//        if (user == null){
//            // 初始化user
//            user = WxDto2User(wxDto);
//            userMapper.save(user);
//            logininfo = User2Logininfo(user);
//            // 将logininfo添加到数据库
//            logininfoMapper.save(logininfo);
//            // 给user赋值
//            user.setLogininfoId(logininfo.getId());
//            // 再次修改user
//            userMapper.upadte(user);
//        }
//        logininfo = logininfoMapper.loadById(user.getLogininfoId());
//        String userUrl = BaseConstants.WxConstant.WX_USER_URL
//                .replace("ACCESS_TOKEN",accessToken)
//                .replace("OPENID",openId);
//        String jsonUser = HttpUtil.httpGet(userUrl);
//        // 使用工具类将jsonUser的数据转移到wxuser中
//        Wxuser wxuser = JSONObject.parseObject(jsonUser, Wxuser.class);
//        // 将user的id赋值给wxuser的userid
//        wxuser.setUserId(user.getId());
//        // 将wxuser添加到数据库
//        wxuserMapper.save(wxuser);
//        // 获得redis的key=token
//        String token = UUID.randomUUID().toString();
//        // 存放数据到redis中
//        redisTemplate.opsForValue().set(token, logininfo,30,TimeUnit.MINUTES);
//        // 装到map中
//        logininfo.setSalt("");
//        logininfo.setPassword("");
//        Map<String, Object> map = new HashMap<>();
//        map.put("token", token);
//        map.put("logininfo", logininfo);
//        return map;
//    }



    /**
    * @Title: loginAccount
    * @Description: 账号登录Jwt登录
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/7/14 18:33
    * @Parameters:
    * @Return
    */
    @Override
    public Map<String, Object> loginAccount(LoginDto loginDto) {
        String password = loginDto.getPassword();
        String type = loginDto.getType();
        String username = loginDto.getUsername();
        // 判断是否为空
        if (StringUtils.isEmpty(password.trim()) || StringUtils.isEmpty(type) || StringUtils.isEmpty(username.trim())) {
            throw new BusinessException("请输入你的账号密码");
        }
        // 根据账号和type去数据库查询
        Logininfo logininfo = logininfoMapper.loadByUsername(username, type);
        // 判断账号是否存在
        if (logininfo == null) {
            throw new BusinessException("账号密码错误");
        }
        // 判断密码是否正确
        String salt = logininfo.getSalt();
        String passwordValue = MD5Utils.encrypByMd5(salt + password);
        if (!passwordValue.equals(logininfo.getPassword())) {
            throw new BusinessException("账号密码错误");
        }
        // 调用方法得到封装好后的map
        Map<String, Object> map = JwtLoginCommon(logininfo);
        return map;
    }

    /**
     * @Title: loginPhoneCode
     * @Description: 手机验证码登录JWT版本
     * @Author: Mr.Jia
     * @Version: 1.0
     * @Date: 2022/7/8 21:58
     * @Parameters:
     * @Return
     */
    @Override
    public Map<String, Object> loginPhoneCode(LoginDto loginDto) {
        String registerCode = loginDto.getRegisterCode();
        String type = loginDto.getType();
        String phone = loginDto.getPhone();
        // 判断是否为空
        if (StringUtils.isEmpty(registerCode.trim()) || StringUtils.isEmpty(type) || StringUtils.isEmpty(phone.trim())) {
            throw new BusinessException("请输入你的手机号及验证码");
        }
        // 判断手机号是否同一个
        String redisPhoneCodeKey = BaseConstants.VerifyCodeConstant.BUSINESS_LOGIN_KEY + phone;
        Object redisPhoneCodeValueTmp = redisTemplate.opsForValue().get(redisPhoneCodeKey);
        if (redisPhoneCodeValueTmp == null) {
            throw new BusinessException("请输入正确的手机号");
        }
        String[] split = redisPhoneCodeValueTmp.toString().split(":");
        String redisPhoneCodeValue = split[1];
        // 判断验证码是否正确
        if (!redisPhoneCodeValue.equalsIgnoreCase(registerCode)) {
            throw new BusinessException("手机验证码错误");
        }
        // 判断用户是否存在
        Logininfo logininfo = logininfoMapper.loadByUsername(phone, type);
        if (logininfo == null) {
            throw new BusinessException("用户不存在");
        }
        // 调用方法得到封装好后的map
        Map<String, Object> map = JwtLoginCommon(logininfo);
        return map;
    }

    /**
     * @Title: wechat
     * @Description: 判断用户微信是否绑定了账号jwt版本
     * @Author: Mr.Jia
     * @Version: 1.0
     * @Date:  2022/7/10 21:06
     * @Parameters:
     * @Return
     */
    @Override
    public AjaxResult wechat(WxDto wxDto) {
        // 判断code是否为空
        String code = wxDto.getCode();
        if (StringUtils.isEmpty(code)) {
            throw new BusinessException("系统异常请稍后再试！！");
        }
        // 获得wx开放平台的用户的基本信息
        String jsonTokenOpenid = HttpUtil.httpGet(BaseConstants.WxConstant.WX_ACCESS_TOKEN_URL
                .replace("APPID", BaseConstants.WxConstant.WX_APPID)
                .replace("SECRET", BaseConstants.WxConstant.WX_SECRET)
                .replace("CODE", code));
        // 将json转换为对象
        JSONObject jsonObject = JSONObject.parseObject(jsonTokenOpenid);
        // 获取openid和access_token值
        String accessToken = jsonObject.getString("access_token");
        String openId = jsonObject.getString("openid");
        // 根据openId从数据库中查询是否有值
        Wxuser wxuser = wxuserMapper.loadByOpenId(openId);
        // 判断wxuser是否存在
        if (wxuser != null) {
            // 根据wxuser的userid获取logininfo对象
            Logininfo logininfo = logininfoMapper.loadByUserId(wxuser.getUserId());
            // 调用方法得到封装好后的map
            Map<String, Object> map = JwtLoginCommon(logininfo);
            return AjaxResult.me().setResult(map);
        }
        // 拼接地址
        String binderUrl = "?accessToken=" + accessToken + "&openId=" + openId;
        // 返回
        return AjaxResult.me().setSuccess(false).setMessage("nobinder").setResult(binderUrl);
    }

    /**
     * @Title: wechatBinder
     * @Description: 给微信用户绑定账号jwt登录（加密数据版本）
     * @Author: Mr.Jia
     * @Version: 1.0
     * @Date:  2022/7/10 21:06
     * @Parameters:
     * @Return
     */
    @Override
    public Map wechatBinder(WxDto wxDto) {
        // 非空判断
        String openId = wxDto.getOpenId();
        String phone = wxDto.getPhone();
        String verifyCode = wxDto.getVerifyCode();
        String accessToken = wxDto.getAccessToken();
        if (StringUtils.isEmpty(openId)
                || StringUtils.isEmpty(phone)
                || StringUtils.isEmpty(verifyCode)
                || StringUtils.isEmpty(accessToken)){
            throw new BusinessException("系统参数为空！！");
        }
        // 根据phone查询user表是否有数据
        User user = userMapper.loadByPhone(phone);
        Logininfo logininfo = null;
        if (user == null){
            // 初始化user
            user = WxDto2User(wxDto);
            userMapper.save(user);
            logininfo = User2Logininfo(user);
            // 将logininfo添加到数据库
            logininfoMapper.save(logininfo);
            // 给user赋值
            user.setLogininfoId(logininfo.getId());
            // 再次修改user
            userMapper.upadte(user);
        }
        logininfo = logininfoMapper.loadById(user.getLogininfoId());
        String userUrl = BaseConstants.WxConstant.WX_USER_URL
                .replace("ACCESS_TOKEN",accessToken)
                .replace("OPENID",openId);
        String jsonUser = HttpUtil.httpGet(userUrl);
        // 使用工具类将jsonUser的数据转移到wxuser中
        Wxuser wxuser = JSONObject.parseObject(jsonUser, Wxuser.class);
        // 将user的id赋值给wxuser的userid
        wxuser.setUserId(user.getId());
        // 将wxuser添加到数据库
        wxuserMapper.save(wxuser);
        // 调用方法得到封装好后的map
        Map<String, Object> map = JwtLoginCommon(logininfo);
        return map;
    }



    /**
    * @Title: JwtLoginCommon
    * @Description: jwt登录公共代码实现
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/7/15 14:01
    * @Parameters:
    * @Return
    */
    public Map<String, Object> JwtLoginCommon(Logininfo logininfo){
        // 创建一个map集合
        Map<String, Object> map = new HashMap<>();
        // 创建一个userinfo对象
        UserInfo userInfo = new UserInfo();
        // 判断是不是员工类型
        if (logininfo.getType() == 0){
            // 获取当前对象的权限
            List<Menu> menus =  menuMapper.loadMenusByLogininfoId(logininfo.getId());
            List<String> permissionSns =  permissionMapper.loadPermissionBylogininfoId(logininfo.getId());
            // 将权限填充到userInfo
            userInfo.setMenus(menus);
            userInfo.setPermissions(permissionSns);
            map.put("menus", menus);
            map.put("permissions", permissionSns);
        }
        // // 将logininfo填充到userInfo
        userInfo.setLogininfo(logininfo);
        // 获取私钥
        PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource(priKey).getFile());
        // 使用jwt进行加密
        String token = JwtUtils.generateTokenExpireInMinutes(userInfo, privateKey, 24*60);
        // 装到map中
        logininfo.setSalt("");
        logininfo.setPassword("");
        map.put("token", token);
        map.put("logininfo", logininfo);
        return map;
    }








    /**
    * @Title: WxDto2User
    * @Description: 初始化user将wxdto中的字段值赋值给user
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/7/10 18:06
    * @Parameters:
    * @Return
    */
    private User WxDto2User(WxDto wxDto) {
        String phone = wxDto.getPhone(); // 电话
        String password = "1";
        // 将registerPhoneDto的值附给user
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        // 获得盐值
        String salt = StrUtils.getComplexRandomString(32);
        // 给密码加密
        String userPassword = MD5Utils.encrypByMd5(salt + password);
        user.setPassword(userPassword);
        // 设置盐值
        user.setSalt(salt);
        return user;
    }


    /**
    * @Title: User2Logininfo
    * @Description: 将user的数据传输到logininfo
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/7/11 9:42
    * @Parameters:
    * @Return
    */
    private Logininfo User2Logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);
        // 设置类型
        logininfo.setType(1);
        return logininfo;
    }
}
